//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include <buola/memory/cmanagedmemory.h>
#include <buola/memory/crbtreememoryalgorithm.h>
#include <buola/utility/random.h>
#include <buola/memory/offset_ptr.h>

using namespace buola;

static const std::size_t MEM_SIZE=1000000;

struct SBlock
{
    uint8_t *mMem;
    std::size_t mSize;
    uint8_t mValue;
};

template<typename tMem>
SBlock random_allocate(tMem &pMem)
{
    SBlock lBlock;
    lBlock.mSize=random::get<std::size_t>(1,1000);
    lBlock.mValue=random::get<uint8_t>();
    lBlock.mMem=reinterpret_cast<uint8_t*>(pMem.Allocate(lBlock.mSize));
    for(int i=0;i<lBlock.mSize;i++)
        lBlock.mMem[i]=lBlock.mValue;
    return lBlock;
}

template<typename tMem>
void deallocate(tMem &pMem,const SBlock &pBlock)
{
    for(int i=0;i<pBlock.mSize;i++)
        if(pBlock.mMem[i]!=pBlock.mValue)
            msg_info() << "error!!!!\n";
    pMem.Deallocate(pBlock.mMem);
}

int main()
{
    typedef CRBTreeMemoryAlgorithm<mutex,offset_ptr<void>> tAlgo;
    typedef CManagedMemory<tAlgo> tMem;
    
    tMem lMem;
    lMem.Init(true,new char[MEM_SIZE],MEM_SIZE);
    
    msg_info() << lMem.FreeMemory() << "\n";
    msg_info() << lMem.size() << "\n";
    
    std::vector<SBlock> lBlocks;

    std::size_t lAccumSize=0;

//    for(int j=0;

    for(int i=0;i<500;i++)
    {
        SBlock lBlock=random_allocate(lMem);
        lAccumSize+=lBlock.mSize;
        lBlocks.push_back(lBlock);
    }
    
    msg_info() << lMem.FreeMemory() << "\n";
    msg_info() << lAccumSize << "\n";
    
    for(int i=0;i<50000;i++)
    {
        int j=random::get<int>(0,499);
        lAccumSize-=lBlocks[j].mSize;
        deallocate(lMem,lBlocks[j]);
        lBlocks[j]=random_allocate(lMem);
        lAccumSize+=lBlocks[j].mSize;
    }
    
    msg_info() << lMem.FreeMemory() << "\n";
    msg_info() << lAccumSize << "\n";
    
    for(int i=0;i<500;i++)
    {
        deallocate(lMem,lBlocks[i]);
    }

    msg_info() << lMem.FreeMemory() << "\n";
}